<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>第2章 变量和基本类型 | ShuangChenYue</title>
    <meta name="generator" content="VuePress 1.9.10">
    <link rel="icon" href="https://cdn.jsdelivr.net/gh/cmty256/imgs-blog@main/logo/白云.38zbldnhh180.jpg">
    <meta name="description" content="满招损，谦受益">
    <meta name="keywords" content="专注于Cpp语言的旅行者">
    
    <link rel="preload" href="/assets/css/0.styles.952d6952.css" as="style"><link rel="preload" href="/assets/js/app.67adcfd9.js" as="script"><link rel="preload" href="/assets/js/4.9aaa1650.js" as="script"><link rel="preload" href="/assets/js/1.5474518c.js" as="script"><link rel="preload" href="/assets/js/3.593d14fc.js" as="script"><link rel="preload" href="/assets/js/48.15ff5726.js" as="script"><link rel="prefetch" href="/assets/js/10.3242746b.js"><link rel="prefetch" href="/assets/js/100.9224de43.js"><link rel="prefetch" href="/assets/js/101.f0d1b059.js"><link rel="prefetch" href="/assets/js/102.996bfc6d.js"><link rel="prefetch" href="/assets/js/103.9bfdbd6f.js"><link rel="prefetch" href="/assets/js/104.8613f283.js"><link rel="prefetch" href="/assets/js/105.aa6e809e.js"><link rel="prefetch" href="/assets/js/106.90192392.js"><link rel="prefetch" href="/assets/js/107.e82a40b7.js"><link rel="prefetch" href="/assets/js/108.994cd438.js"><link rel="prefetch" href="/assets/js/109.ec15acc2.js"><link rel="prefetch" href="/assets/js/11.c04b41c1.js"><link rel="prefetch" href="/assets/js/110.c32d8576.js"><link rel="prefetch" href="/assets/js/111.453b5d50.js"><link rel="prefetch" href="/assets/js/112.ffbdb3a4.js"><link rel="prefetch" href="/assets/js/113.12b8ad7d.js"><link rel="prefetch" href="/assets/js/114.899d2998.js"><link rel="prefetch" href="/assets/js/115.b7ad9576.js"><link rel="prefetch" href="/assets/js/116.a8394748.js"><link rel="prefetch" href="/assets/js/117.0edfe25b.js"><link rel="prefetch" href="/assets/js/118.9161b1fe.js"><link rel="prefetch" href="/assets/js/119.be59e21b.js"><link rel="prefetch" href="/assets/js/12.41437bf6.js"><link rel="prefetch" href="/assets/js/120.bcf439fb.js"><link rel="prefetch" href="/assets/js/121.c3d251b8.js"><link rel="prefetch" href="/assets/js/122.62b1caba.js"><link rel="prefetch" href="/assets/js/123.787c2ab0.js"><link rel="prefetch" href="/assets/js/124.a880746f.js"><link rel="prefetch" href="/assets/js/125.d8edfe7b.js"><link rel="prefetch" href="/assets/js/126.4ff01546.js"><link rel="prefetch" href="/assets/js/127.9416d1ff.js"><link rel="prefetch" href="/assets/js/128.01a4a7a0.js"><link rel="prefetch" href="/assets/js/129.76876665.js"><link rel="prefetch" href="/assets/js/13.922328e9.js"><link rel="prefetch" href="/assets/js/130.7f631dd9.js"><link rel="prefetch" href="/assets/js/131.c9e0fde9.js"><link rel="prefetch" href="/assets/js/132.1c04cde5.js"><link rel="prefetch" href="/assets/js/133.e8f381cd.js"><link rel="prefetch" href="/assets/js/134.03d19f8b.js"><link rel="prefetch" href="/assets/js/135.44607494.js"><link rel="prefetch" href="/assets/js/136.6a1eb3c9.js"><link rel="prefetch" href="/assets/js/137.27898fd1.js"><link rel="prefetch" href="/assets/js/138.5bc0cf54.js"><link rel="prefetch" href="/assets/js/139.c2d1addc.js"><link rel="prefetch" href="/assets/js/14.e54d7526.js"><link rel="prefetch" href="/assets/js/140.052ec8e4.js"><link rel="prefetch" href="/assets/js/141.131abb5a.js"><link rel="prefetch" href="/assets/js/142.6ba6c07b.js"><link rel="prefetch" href="/assets/js/143.5dd51d22.js"><link rel="prefetch" href="/assets/js/144.b45afca8.js"><link rel="prefetch" href="/assets/js/145.faa9fb04.js"><link rel="prefetch" href="/assets/js/146.b54c024d.js"><link rel="prefetch" href="/assets/js/147.a1223242.js"><link rel="prefetch" href="/assets/js/148.4767bcb2.js"><link rel="prefetch" href="/assets/js/149.b65ab046.js"><link rel="prefetch" href="/assets/js/15.7082a3da.js"><link rel="prefetch" href="/assets/js/150.9bd8c175.js"><link rel="prefetch" href="/assets/js/151.9f830e96.js"><link rel="prefetch" href="/assets/js/152.41cde7f0.js"><link rel="prefetch" href="/assets/js/153.f57d65e0.js"><link rel="prefetch" href="/assets/js/154.5d7c8d51.js"><link rel="prefetch" href="/assets/js/155.0ae99532.js"><link rel="prefetch" href="/assets/js/156.5a54e043.js"><link rel="prefetch" href="/assets/js/157.c25b5d40.js"><link rel="prefetch" href="/assets/js/158.aa025b46.js"><link rel="prefetch" href="/assets/js/159.47939d88.js"><link rel="prefetch" href="/assets/js/16.fc775b7b.js"><link rel="prefetch" href="/assets/js/160.f8624459.js"><link rel="prefetch" href="/assets/js/161.7a075dc2.js"><link rel="prefetch" href="/assets/js/162.1d48f266.js"><link rel="prefetch" href="/assets/js/163.5d68a99f.js"><link rel="prefetch" href="/assets/js/164.1262d0e5.js"><link rel="prefetch" href="/assets/js/165.2ccf0bdd.js"><link rel="prefetch" href="/assets/js/166.21ece4d9.js"><link rel="prefetch" href="/assets/js/167.bf8adb95.js"><link rel="prefetch" href="/assets/js/168.1cb8440d.js"><link rel="prefetch" href="/assets/js/169.1dd1e396.js"><link rel="prefetch" href="/assets/js/17.ecc7be70.js"><link rel="prefetch" href="/assets/js/170.c29ec18f.js"><link rel="prefetch" href="/assets/js/171.38820827.js"><link rel="prefetch" href="/assets/js/172.bbc8ffc6.js"><link rel="prefetch" href="/assets/js/173.470e21e7.js"><link rel="prefetch" href="/assets/js/174.3c2df318.js"><link rel="prefetch" href="/assets/js/175.d2690cdb.js"><link rel="prefetch" href="/assets/js/176.9ca64696.js"><link rel="prefetch" href="/assets/js/177.76f3271d.js"><link rel="prefetch" href="/assets/js/178.d7d9def2.js"><link rel="prefetch" href="/assets/js/179.b5644743.js"><link rel="prefetch" href="/assets/js/18.31fe7ecd.js"><link rel="prefetch" href="/assets/js/180.7592d5ef.js"><link rel="prefetch" href="/assets/js/181.5cb77d35.js"><link rel="prefetch" href="/assets/js/182.6fa5633c.js"><link rel="prefetch" href="/assets/js/183.b3a53d1b.js"><link rel="prefetch" href="/assets/js/184.3815c537.js"><link rel="prefetch" href="/assets/js/185.bcf4ab71.js"><link rel="prefetch" href="/assets/js/186.1cc02f6d.js"><link rel="prefetch" href="/assets/js/187.8b425fb7.js"><link rel="prefetch" href="/assets/js/188.44ccbd02.js"><link rel="prefetch" href="/assets/js/189.353b35e3.js"><link rel="prefetch" href="/assets/js/19.520992d5.js"><link rel="prefetch" href="/assets/js/190.c284595f.js"><link rel="prefetch" href="/assets/js/191.788ecc2d.js"><link rel="prefetch" href="/assets/js/192.712a164e.js"><link rel="prefetch" href="/assets/js/193.da58aba3.js"><link rel="prefetch" href="/assets/js/194.6b1b1f4d.js"><link rel="prefetch" href="/assets/js/195.c31d5c39.js"><link rel="prefetch" href="/assets/js/196.f6670c4d.js"><link rel="prefetch" href="/assets/js/197.5a1f50ab.js"><link rel="prefetch" href="/assets/js/2.ab565158.js"><link rel="prefetch" href="/assets/js/20.69e29cdc.js"><link rel="prefetch" href="/assets/js/21.2fd424ad.js"><link rel="prefetch" href="/assets/js/22.d4c0be54.js"><link rel="prefetch" href="/assets/js/23.4bb90ecc.js"><link rel="prefetch" href="/assets/js/24.c01be6b2.js"><link rel="prefetch" href="/assets/js/25.c8833687.js"><link rel="prefetch" href="/assets/js/26.8042b555.js"><link rel="prefetch" href="/assets/js/27.0d5fa4c0.js"><link rel="prefetch" href="/assets/js/28.f9735b8b.js"><link rel="prefetch" href="/assets/js/29.3af53626.js"><link rel="prefetch" href="/assets/js/30.5f1b56d1.js"><link rel="prefetch" href="/assets/js/31.544b2649.js"><link rel="prefetch" href="/assets/js/32.aa321988.js"><link rel="prefetch" href="/assets/js/33.6aba2c86.js"><link rel="prefetch" href="/assets/js/34.e1bbff24.js"><link rel="prefetch" href="/assets/js/35.233f76e0.js"><link rel="prefetch" href="/assets/js/36.cb773972.js"><link rel="prefetch" href="/assets/js/37.393d9c59.js"><link rel="prefetch" href="/assets/js/38.e2d530c5.js"><link rel="prefetch" href="/assets/js/39.acaf1cc0.js"><link rel="prefetch" href="/assets/js/40.358f731e.js"><link rel="prefetch" href="/assets/js/41.ded24b7e.js"><link rel="prefetch" href="/assets/js/42.b9f683c3.js"><link rel="prefetch" href="/assets/js/43.c8fb3e66.js"><link rel="prefetch" href="/assets/js/44.633142da.js"><link rel="prefetch" href="/assets/js/45.6095e772.js"><link rel="prefetch" href="/assets/js/46.421d8c7a.js"><link rel="prefetch" href="/assets/js/47.da50fe47.js"><link rel="prefetch" href="/assets/js/49.b662e624.js"><link rel="prefetch" href="/assets/js/5.c1b8a209.js"><link rel="prefetch" href="/assets/js/50.a8bc75df.js"><link rel="prefetch" href="/assets/js/51.51e36ae7.js"><link rel="prefetch" href="/assets/js/52.54cc6e51.js"><link rel="prefetch" href="/assets/js/53.4173561d.js"><link rel="prefetch" href="/assets/js/54.7cab8416.js"><link rel="prefetch" href="/assets/js/55.3d7317d3.js"><link rel="prefetch" href="/assets/js/56.3c22255b.js"><link rel="prefetch" href="/assets/js/57.18e46e30.js"><link rel="prefetch" href="/assets/js/58.aad57f31.js"><link rel="prefetch" href="/assets/js/59.7897f6a7.js"><link rel="prefetch" href="/assets/js/6.3131f88a.js"><link rel="prefetch" href="/assets/js/60.5cd0051a.js"><link rel="prefetch" href="/assets/js/61.d9606403.js"><link rel="prefetch" href="/assets/js/62.aede9df0.js"><link rel="prefetch" href="/assets/js/63.2c30e554.js"><link rel="prefetch" href="/assets/js/64.18228ab7.js"><link rel="prefetch" href="/assets/js/65.27cb3fba.js"><link rel="prefetch" href="/assets/js/66.2fa6c2dc.js"><link rel="prefetch" href="/assets/js/67.d274a8df.js"><link rel="prefetch" href="/assets/js/68.3069cfcf.js"><link rel="prefetch" href="/assets/js/69.4c28600f.js"><link rel="prefetch" href="/assets/js/7.89e6165d.js"><link rel="prefetch" href="/assets/js/70.4175440c.js"><link rel="prefetch" href="/assets/js/71.2ee6b435.js"><link rel="prefetch" href="/assets/js/72.c75e3bb8.js"><link rel="prefetch" href="/assets/js/73.6f8b8211.js"><link rel="prefetch" href="/assets/js/74.6c7720cf.js"><link rel="prefetch" href="/assets/js/75.cccfb229.js"><link rel="prefetch" href="/assets/js/76.f022e5da.js"><link rel="prefetch" href="/assets/js/77.dab46206.js"><link rel="prefetch" href="/assets/js/78.ca574b2a.js"><link rel="prefetch" href="/assets/js/79.3d75e618.js"><link rel="prefetch" href="/assets/js/80.091749b1.js"><link rel="prefetch" href="/assets/js/81.14db0e21.js"><link rel="prefetch" href="/assets/js/82.8a2b1809.js"><link rel="prefetch" href="/assets/js/83.84a4b599.js"><link rel="prefetch" href="/assets/js/84.11d7c222.js"><link rel="prefetch" href="/assets/js/85.273d4388.js"><link rel="prefetch" href="/assets/js/86.fb40e20c.js"><link rel="prefetch" href="/assets/js/87.3316639e.js"><link rel="prefetch" href="/assets/js/88.dfc52200.js"><link rel="prefetch" href="/assets/js/89.8d615f6e.js"><link rel="prefetch" href="/assets/js/90.1d9f08bb.js"><link rel="prefetch" href="/assets/js/91.566813e7.js"><link rel="prefetch" href="/assets/js/92.d13c6f41.js"><link rel="prefetch" href="/assets/js/93.845c42a0.js"><link rel="prefetch" href="/assets/js/94.20a37b77.js"><link rel="prefetch" href="/assets/js/95.1a498005.js"><link rel="prefetch" href="/assets/js/96.39fa7f4b.js"><link rel="prefetch" href="/assets/js/97.50f7170e.js"><link rel="prefetch" href="/assets/js/98.dd2e15d6.js"><link rel="prefetch" href="/assets/js/99.ef7ea06a.js"><link rel="prefetch" href="/assets/js/vendors~docsearch.ae6b1de9.js">
    <link rel="stylesheet" href="/assets/css/0.styles.952d6952.css">
  </head>
  <body class="theme-mode-light">
    <div id="app" data-server-rendered="true"><div class="theme-container sidebar-open have-rightmenu"><header class="navbar blur"><div title="目录" class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="https://cdn.jsdelivr.net/gh/cmty256/imgs-blog@main/logo/白云.38zbldnhh180.jpg" alt="ShuangChenYue" class="logo"> <span class="site-name can-hide">ShuangChenYue</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="CPP语言" class="dropdown-title"><!----> <span class="title" style="display:;">CPP语言</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/c5bdd8/" class="nav-link">Cpp之旅</a></li><li class="dropdown-item"><!----> <a href="/pages/279e62/" aria-current="page" class="nav-link router-link-exact-active router-link-active">Cpp专栏</a></li><li class="dropdown-item"><!----> <a href="/pages/801755/" class="nav-link">Effective_CPP</a></li><li class="dropdown-item"><!----> <a href="/pages/6b2468/" class="nav-link">muduo网络库</a></li><li class="dropdown-item"><!----> <a href="/pages/5f8c9f/" class="nav-link">Unix环境高级编程</a></li><li class="dropdown-item"><!----> <a href="/pages/3f1d21/" class="nav-link">Cpp提高编程</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="计算机基础" class="dropdown-title"><!----> <span class="title" style="display:;">计算机基础</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/7b1cb2/" class="nav-link">计算机网络</a></li><li class="dropdown-item"><!----> <a href="/pages/6048a8/" class="nav-link">操作系统</a></li><li class="dropdown-item"><!----> <a href="/pages/3b34ba/" class="nav-link">数据结构</a></li><li class="dropdown-item"><!----> <a href="/pages/412fe7/" class="nav-link">Linux</a></li><li class="dropdown-item"><!----> <a href="/pages/2dcfa1/" class="nav-link">算法</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="数据库" class="dropdown-title"><!----> <span class="title" style="display:;">数据库</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/efa3f2/" class="nav-link">基础篇</a></li><li class="dropdown-item"><!----> <a href="/pages/ccc445/" class="nav-link">MySql</a></li><li class="dropdown-item"><!----> <a href="/pages/54616e/" class="nav-link">Redis</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="嵌入式软件开发" class="dropdown-title"><!----> <span class="title" style="display:;">嵌入式软件开发</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/d142c2/" class="nav-link">电子嵌入式通信协议</a></li><li class="dropdown-item"><!----> <a href="/pages/4c6bf3/" class="nav-link">深入浅出SSD</a></li><li class="dropdown-item"><!----> <a href="/pages/d3f36a/" class="nav-link">文件系统</a></li><li class="dropdown-item"><!----> <a href="/pages/e0cca7/" class="nav-link">汇编语言</a></li><li class="dropdown-item"><!----> <a href="/pages/fab2d7/" class="nav-link">STM32</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="开发日常" class="dropdown-title"><!----> <span class="title" style="display:;">开发日常</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/e472d1/" class="nav-link">随笔（持续更新）</a></li><li class="dropdown-item"><!----> <a href="/pages/71f6ae/" class="nav-link">Git知识总结</a></li><li class="dropdown-item"><!----> <a href="/pages/db6fb8/" class="nav-link">Git备忘清单</a></li><li class="dropdown-item"><!----> <a href="/pages/e1081f/" class="nav-link">Git 创建删除远程分支</a></li><li class="dropdown-item"><!----> <a href="/pages/777b8a/" class="nav-link">nvm使用小结</a></li><li class="dropdown-item"><!----> <a href="/pages/ee770e/" class="nav-link">虚拟机固定 IP 地址</a></li><li class="dropdown-item"><!----> <a href="/pages/1ab9a6/" class="nav-link">Shell 脚本学习笔记</a></li><li class="dropdown-item"><!----> <a href="/pages/411aa4/" class="nav-link">VScode 插件 CodeGeeX 使用教程</a></li><li class="dropdown-item"><!----> <a href="/pages/0d525d/" class="nav-link">KylinV10 将项目上传至 Github教程</a></li><li class="dropdown-item"><!----> <a href="/pages/907786/" class="nav-link">KylinV10 安装 MySQL 教程（可防踩雷）</a></li><li class="dropdown-item"><!----> <a href="/pages/a2d21e/" class="nav-link">kylinV10-SP1 安装 QT</a></li><li class="dropdown-item"><!----> <a href="/pages/b561cf/" class="nav-link">高并发内存池</a></li><li class="dropdown-item"><!----> <a href="/pages/6ab6d1/" class="nav-link">USBGUARD 项目编译环境配置</a></li><li class="dropdown-item"><!----> <a href="/pages/883f02/" class="nav-link">Power_Destory 项目</a></li><li class="dropdown-item"><!----> <a href="/pages/479472/" class="nav-link">U 盘清除工具编译教程</a></li><li class="dropdown-item"><!----> <a href="/pages/9c4241/" class="nav-link">个人博客代码推送教程</a></li><li class="dropdown-item"><!----> <a href="/pages/3ad765/" class="nav-link">SVN Trunk Branches的Merge操作</a></li><li class="dropdown-item"><!----> <a href="/pages/0c0ca8/" class="nav-link">如何高效阅读嵌入式项目代码</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端学习" class="dropdown-title"><!----> <span class="title" style="display:;">前端学习</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/99897f/" class="nav-link">HTML与CSS</a></li><li class="dropdown-item"><!----> <a href="/pages/51542d/" class="nav-link">JS学习</a></li><li class="dropdown-item"><!----> <a href="/pages/803f9d/" class="nav-link">Vue3入门</a></li><li class="dropdown-item"><!----> <a href="/pages/ca4cfb/" class="nav-link">Vue3进阶</a></li><li class="dropdown-item"><!----> <a href="/pages/50e8d3/" class="nav-link">黑马Vue3</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="MFC" class="dropdown-title"><!----> <span class="title" style="display:;">MFC</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/a4b108/" class="nav-link">MFC编程随记</a></li><li class="dropdown-item"><!----> <a href="/pages/41acbd/" class="nav-link">MFC实现ini配置文件的读取</a></li><li class="dropdown-item"><!----> <a href="/pages/951a7a/" class="nav-link">MFC实现点击列表头排序</a></li><li class="dropdown-item"><!----> <a href="/pages/a8598f/" class="nav-link">贴图法美化Button按钮</a></li><li class="dropdown-item"><!----> <a href="/pages/054516/" class="nav-link">MFC使用细节</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="闪存" class="dropdown-title"><!----> <span class="title" style="display:;">闪存</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/b925b8/" class="nav-link">如何高效阅读嵌入式项目代码</a></li><li class="dropdown-item"><!----> <a href="/pages/28ec23/" class="nav-link">NAND Flash</a></li><li class="dropdown-item"><!----> <a href="/pages/62bf40/" class="nav-link">ARM 处理器</a></li><li class="dropdown-item"><!----> <a href="/pages/1a9374/" class="nav-link">嵌入式基础知识-存储器</a></li><li class="dropdown-item"><!----> <a href="/pages/aac5e3/" class="nav-link">闪存存储和制造技术概述</a></li><li class="dropdown-item"><!----> <a href="/pages/8f6056/" class="nav-link">芯片IO驱动力</a></li><li class="dropdown-item"><!----> <a href="/pages/d146b8/" class="nav-link">主流先进封装技术介绍</a></li><li class="dropdown-item"><!----> <a href="/pages/16f0ba/" class="nav-link">NAND Flash基础</a></li><li class="dropdown-item"><!----> <a href="/pages/90d8d0/" class="nav-link">基于PA算法的FTL引导</a></li><li class="dropdown-item"><!----> <a href="/pages/eb672b/" class="nav-link">SD逻辑擦除和物理擦除</a></li><li class="dropdown-item"><!----> <a href="/pages/747121/" class="nav-link">NAND Flash的SDR、ONFI、DDR接口</a></li><li class="dropdown-item"><!----> <a href="/pages/1eb351/" class="nav-link">【详解】Nand Flash必看知识</a></li><li class="dropdown-item"><!----> <a href="/pages/d2512a/" class="nav-link">【两万字详解】Nand Flash必看知识</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="面经" class="dropdown-title"><!----> <span class="title" style="display:;">面经</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/d69946/" class="nav-link">虎牙C++技术面经</a></li><li class="dropdown-item"><!----> <a href="/pages/29251d/" class="nav-link">金山一面复习</a></li><li class="dropdown-item"><!----> <a href="/pages/c7c01f/" class="nav-link">完美世界秋招 C++ 游戏开发面经(Cpp部分)</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="其它" class="dropdown-title"><!----> <span class="title" style="display:;">其它</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/fa256e/" class="nav-link">博客搭建</a></li><li class="dropdown-item"><!----> <a href="/pages/335531/" class="nav-link">网站收藏箱</a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <div class="sidebar-hover-trigger"></div> <aside class="sidebar" style="display:none;"><!----> <nav class="nav-links"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="CPP语言" class="dropdown-title"><!----> <span class="title" style="display:;">CPP语言</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/c5bdd8/" class="nav-link">Cpp之旅</a></li><li class="dropdown-item"><!----> <a href="/pages/279e62/" aria-current="page" class="nav-link router-link-exact-active router-link-active">Cpp专栏</a></li><li class="dropdown-item"><!----> <a href="/pages/801755/" class="nav-link">Effective_CPP</a></li><li class="dropdown-item"><!----> <a href="/pages/6b2468/" class="nav-link">muduo网络库</a></li><li class="dropdown-item"><!----> <a href="/pages/5f8c9f/" class="nav-link">Unix环境高级编程</a></li><li class="dropdown-item"><!----> <a href="/pages/3f1d21/" class="nav-link">Cpp提高编程</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="计算机基础" class="dropdown-title"><!----> <span class="title" style="display:;">计算机基础</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/7b1cb2/" class="nav-link">计算机网络</a></li><li class="dropdown-item"><!----> <a href="/pages/6048a8/" class="nav-link">操作系统</a></li><li class="dropdown-item"><!----> <a href="/pages/3b34ba/" class="nav-link">数据结构</a></li><li class="dropdown-item"><!----> <a href="/pages/412fe7/" class="nav-link">Linux</a></li><li class="dropdown-item"><!----> <a href="/pages/2dcfa1/" class="nav-link">算法</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="数据库" class="dropdown-title"><!----> <span class="title" style="display:;">数据库</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/efa3f2/" class="nav-link">基础篇</a></li><li class="dropdown-item"><!----> <a href="/pages/ccc445/" class="nav-link">MySql</a></li><li class="dropdown-item"><!----> <a href="/pages/54616e/" class="nav-link">Redis</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="嵌入式软件开发" class="dropdown-title"><!----> <span class="title" style="display:;">嵌入式软件开发</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/d142c2/" class="nav-link">电子嵌入式通信协议</a></li><li class="dropdown-item"><!----> <a href="/pages/4c6bf3/" class="nav-link">深入浅出SSD</a></li><li class="dropdown-item"><!----> <a href="/pages/d3f36a/" class="nav-link">文件系统</a></li><li class="dropdown-item"><!----> <a href="/pages/e0cca7/" class="nav-link">汇编语言</a></li><li class="dropdown-item"><!----> <a href="/pages/fab2d7/" class="nav-link">STM32</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="开发日常" class="dropdown-title"><!----> <span class="title" style="display:;">开发日常</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/e472d1/" class="nav-link">随笔（持续更新）</a></li><li class="dropdown-item"><!----> <a href="/pages/71f6ae/" class="nav-link">Git知识总结</a></li><li class="dropdown-item"><!----> <a href="/pages/db6fb8/" class="nav-link">Git备忘清单</a></li><li class="dropdown-item"><!----> <a href="/pages/e1081f/" class="nav-link">Git 创建删除远程分支</a></li><li class="dropdown-item"><!----> <a href="/pages/777b8a/" class="nav-link">nvm使用小结</a></li><li class="dropdown-item"><!----> <a href="/pages/ee770e/" class="nav-link">虚拟机固定 IP 地址</a></li><li class="dropdown-item"><!----> <a href="/pages/1ab9a6/" class="nav-link">Shell 脚本学习笔记</a></li><li class="dropdown-item"><!----> <a href="/pages/411aa4/" class="nav-link">VScode 插件 CodeGeeX 使用教程</a></li><li class="dropdown-item"><!----> <a href="/pages/0d525d/" class="nav-link">KylinV10 将项目上传至 Github教程</a></li><li class="dropdown-item"><!----> <a href="/pages/907786/" class="nav-link">KylinV10 安装 MySQL 教程（可防踩雷）</a></li><li class="dropdown-item"><!----> <a href="/pages/a2d21e/" class="nav-link">kylinV10-SP1 安装 QT</a></li><li class="dropdown-item"><!----> <a href="/pages/b561cf/" class="nav-link">高并发内存池</a></li><li class="dropdown-item"><!----> <a href="/pages/6ab6d1/" class="nav-link">USBGUARD 项目编译环境配置</a></li><li class="dropdown-item"><!----> <a href="/pages/883f02/" class="nav-link">Power_Destory 项目</a></li><li class="dropdown-item"><!----> <a href="/pages/479472/" class="nav-link">U 盘清除工具编译教程</a></li><li class="dropdown-item"><!----> <a href="/pages/9c4241/" class="nav-link">个人博客代码推送教程</a></li><li class="dropdown-item"><!----> <a href="/pages/3ad765/" class="nav-link">SVN Trunk Branches的Merge操作</a></li><li class="dropdown-item"><!----> <a href="/pages/0c0ca8/" class="nav-link">如何高效阅读嵌入式项目代码</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端学习" class="dropdown-title"><!----> <span class="title" style="display:;">前端学习</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/99897f/" class="nav-link">HTML与CSS</a></li><li class="dropdown-item"><!----> <a href="/pages/51542d/" class="nav-link">JS学习</a></li><li class="dropdown-item"><!----> <a href="/pages/803f9d/" class="nav-link">Vue3入门</a></li><li class="dropdown-item"><!----> <a href="/pages/ca4cfb/" class="nav-link">Vue3进阶</a></li><li class="dropdown-item"><!----> <a href="/pages/50e8d3/" class="nav-link">黑马Vue3</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="MFC" class="dropdown-title"><!----> <span class="title" style="display:;">MFC</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/a4b108/" class="nav-link">MFC编程随记</a></li><li class="dropdown-item"><!----> <a href="/pages/41acbd/" class="nav-link">MFC实现ini配置文件的读取</a></li><li class="dropdown-item"><!----> <a href="/pages/951a7a/" class="nav-link">MFC实现点击列表头排序</a></li><li class="dropdown-item"><!----> <a href="/pages/a8598f/" class="nav-link">贴图法美化Button按钮</a></li><li class="dropdown-item"><!----> <a href="/pages/054516/" class="nav-link">MFC使用细节</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="闪存" class="dropdown-title"><!----> <span class="title" style="display:;">闪存</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/b925b8/" class="nav-link">如何高效阅读嵌入式项目代码</a></li><li class="dropdown-item"><!----> <a href="/pages/28ec23/" class="nav-link">NAND Flash</a></li><li class="dropdown-item"><!----> <a href="/pages/62bf40/" class="nav-link">ARM 处理器</a></li><li class="dropdown-item"><!----> <a href="/pages/1a9374/" class="nav-link">嵌入式基础知识-存储器</a></li><li class="dropdown-item"><!----> <a href="/pages/aac5e3/" class="nav-link">闪存存储和制造技术概述</a></li><li class="dropdown-item"><!----> <a href="/pages/8f6056/" class="nav-link">芯片IO驱动力</a></li><li class="dropdown-item"><!----> <a href="/pages/d146b8/" class="nav-link">主流先进封装技术介绍</a></li><li class="dropdown-item"><!----> <a href="/pages/16f0ba/" class="nav-link">NAND Flash基础</a></li><li class="dropdown-item"><!----> <a href="/pages/90d8d0/" class="nav-link">基于PA算法的FTL引导</a></li><li class="dropdown-item"><!----> <a href="/pages/eb672b/" class="nav-link">SD逻辑擦除和物理擦除</a></li><li class="dropdown-item"><!----> <a href="/pages/747121/" class="nav-link">NAND Flash的SDR、ONFI、DDR接口</a></li><li class="dropdown-item"><!----> <a href="/pages/1eb351/" class="nav-link">【详解】Nand Flash必看知识</a></li><li class="dropdown-item"><!----> <a href="/pages/d2512a/" class="nav-link">【两万字详解】Nand Flash必看知识</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="面经" class="dropdown-title"><!----> <span class="title" style="display:;">面经</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/d69946/" class="nav-link">虎牙C++技术面经</a></li><li class="dropdown-item"><!----> <a href="/pages/29251d/" class="nav-link">金山一面复习</a></li><li class="dropdown-item"><!----> <a href="/pages/c7c01f/" class="nav-link">完美世界秋招 C++ 游戏开发面经(Cpp部分)</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="其它" class="dropdown-title"><!----> <span class="title" style="display:;">其它</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/pages/fa256e/" class="nav-link">博客搭建</a></li><li class="dropdown-item"><!----> <a href="/pages/335531/" class="nav-link">网站收藏箱</a></li></ul></div></div> <!----></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Cpp之旅</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>Cpp专栏</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/pages/279e62/" aria-current="page" class="active sidebar-link">第2章 变量和基本类型</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level2"><a href="/pages/279e62/#_2-1-基本内置类型" class="sidebar-link">2.1 基本内置类型</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-1-1-算术类型" class="sidebar-link">2.1.1 算术类型</a></li><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-1-1-练习" class="sidebar-link">2.1.1 练习</a></li><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-1-2-类型转换" class="sidebar-link">2.1.2 类型转换</a></li><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-1-3-字面值常量" class="sidebar-link">2.1.3 字面值常量</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/279e62/#_2-2-变量" class="sidebar-link">2.2 变量</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-2-1-变量定义" class="sidebar-link">2.2.1 变量定义</a></li><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-2-2-变量声明和定义的关系" class="sidebar-link">2.2.2 变量声明和定义的关系</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/279e62/#_2-3-复合类型" class="sidebar-link">2.3 复合类型</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-3-1-引用" class="sidebar-link">2.3.1 引用</a></li><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-3-2-指针" class="sidebar-link">2.3.2 指针</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/279e62/#_2-4-const限定符" class="sidebar-link">2.4 const限定符</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-4-1-const-的引用" class="sidebar-link">2.4.1 const 的引用</a></li><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-4-2-指针和-const" class="sidebar-link">2.4.2 指针和 const</a></li><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-4-3-顶层-const" class="sidebar-link">2.4.3 顶层 const</a></li><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-4-4-constexpr-和常量表达式" class="sidebar-link">2.4.4 constexpr 和常量表达式</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/279e62/#_2-5-处理类型" class="sidebar-link">2.5 处理类型</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-5-1-类型别名" class="sidebar-link">2.5.1 类型别名</a></li><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-5-2-auto-类型说明符" class="sidebar-link">2.5.2 auto 类型说明符</a></li><li class="sidebar-sub-header level3"><a href="/pages/279e62/#_2-5-3-decltype-类型指示符" class="sidebar-link">2.5.3 decltype 类型指示符</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/279e62/#小结" class="sidebar-link">小结</a></li></ul></li><li><a href="/pages/518856/" class="sidebar-link">Cpp11新标准</a></li><li><a href="/pages/2f7f31/" class="sidebar-link">探索C++14新特性：更强大、更高效的编程</a></li><li><a href="/pages/c6fc35/" class="sidebar-link">C++17 新特性</a></li><li><a href="/pages/7dd194/" class="sidebar-link">协程</a></li><li><a href="/pages/e769c6/" class="sidebar-link">C++ 备忘清单</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Effetcive_CPP</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>muduo网络库</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Unix环境高级编程</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Cpp提高编程</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <div><main class="page"><div class="theme-vdoing-wrapper "><div class="articleInfo-wrap" data-v-06225672><div class="articleInfo" data-v-06225672><ul class="breadcrumbs" data-v-06225672><li data-v-06225672><a href="/" title="首页" class="iconfont icon-home router-link-active" data-v-06225672></a></li> <li data-v-06225672><span data-v-06225672>CPP语言</span></li><li data-v-06225672><span data-v-06225672>Cpp专栏</span></li></ul> <div class="info" data-v-06225672><div title="作者" class="author iconfont icon-touxiang" data-v-06225672><a href="javascript:;" data-v-06225672>霜晨月</a></div> <div title="创建时间" class="date iconfont icon-riqi" data-v-06225672><a href="javascript:;" data-v-06225672>2023-12-01</a></div> <!----></div></div></div> <!----> <div class="content-wrapper"><div class="right-menu-wrapper"><div class="right-menu-margin"><div class="right-menu-title">目录</div> <div class="right-menu-content"></div></div></div> <h1><img src="">第2章 变量和基本类型<!----></h1> <!----> <div class="theme-vdoing-content content__default"><h1 id="第2章-变量和基本类型"><a href="#第2章-变量和基本类型" class="header-anchor">#</a> 第2章 变量和基本类型</h1> <p>本章介绍了Cpp的几种典型数据类型，它们分别是：</p> <ul><li>基本内置类型</li> <li>复合类型</li> <li>自定义数据结构</li></ul> <p>其中，char、 int、 long、 float、 double、 bool 是最常见的基本内置类型；</p> <p>引用和指针是两种最重要的复合类型；struct 关键字和 class 关键字则常用于声明用户自定义的数据结构。</p> <h2 id="_2-1-基本内置类型"><a href="#_2-1-基本内置类型" class="header-anchor">#</a> 2.1 基本内置类型</h2> <p><strong>基本数据类型主要有算术类型和空类型（void）：</strong></p> <ul><li>算数类型：字符、整数型、布尔值、浮点数。</li> <li>空类型：不对应具体值，例如：函数不返回任何值时使用空类型作为返回类型。</li></ul> <h3 id="_2-1-1-算术类型"><a href="#_2-1-1-算术类型" class="header-anchor">#</a> 2.1.1 算术类型</h3> <p><strong>算术类型可分两类：</strong></p> <ul><li>整型（integral type ，包括字符和布尔类型）；</li> <li>浮点型。</li></ul> <blockquote><p>尺寸：该类型数据所占的比特数</p></blockquote> <p>表 2.1 列出了 Cpp 标准规定的尺寸的最小值，同时允许编译器赋予这些类型更大的尺寸。</p> <p><img alt="1701228197022" data-src="https://cdn.jsdelivr.net/gh/xiaose-code/Pictures@main/img/1701228197022.webp" loading="lazy" class="lazy"></p> <p><strong>==Cpp语言规定一个 int 至少和一个 short 一样大，一个 long 至少和一个 int 一样大，一个 long long 至少和一个 long 一样大。==</strong>（long long 是在 Cpp11 中新定义的）</p> <blockquote><p>可寻址的最小内存块称为“字节”。</p></blockquote> <blockquote><p>存储的基本单元称为“字（word）”</p></blockquote> <blockquote><p>字由32比特（4字节）或64比特（8字节）构成。即 4字节=字32比特；8字节=字64比特</p> <p><strong>==关系：1个字 = 4字节 = 32比特==</strong></p></blockquote> <p>在一个字节为8比特，字为32比特的机器上，（其实就是4字节）一个字的内存区域如下：</p> <p><img alt="1701228880409" data-src="https://cdn.jsdelivr.net/gh/xiaose-code/Pictures@main/img/1701228880409.webp" loading="lazy" class="lazy"></p> <p>其中，左侧是字节的地址，右侧是字节中8比特的具体内容。</p> <hr> <p><strong>浮点型可分为：</strong></p> <ul><li>单精度；</li> <li>双精度；</li> <li>扩展精度值。</li></ul> <p>通常：</p> <ul><li>float = 1个字（32比特）</li> <li>double = 2个字（64比特）</li> <li>long double = 3个字（96比特）或者4个字（128比特）</li></ul> <p><strong>带符号类型和无符号类型</strong></p> <ul><li>带符号类型（signed）：可以表示整数、负数或者0
<ul><li>int、short、long、long long 都是带符号的</li></ul></li> <li>无符号类型（unsigned）：仅能表示大于等于0的值
<ul><li>在其他类型前面添加 unsigned 就可以的到无符号类型</li></ul></li></ul> <p>==<strong>建议：如何选择类型</strong>==</p> <ul><li>当明确知晓数值不可能为负时，选用无符号类型；</li> <li>使用 int 执行整数运算。在实际应用中，long 一般和 int 有一样的尺寸。如果你的数值超过了 int 的表示范围，选用 long long。</li> <li>在算术表达式中不要使用 char 和 bool，只有在存放字符或布尔值时才使用它们。如果使用一个不大的整数，请明确指定它的类型是 signed char 或者 unsigned char。</li> <li>执行浮点数运算选用 double，这是因为 float 通常精度不够而且双精度浮点数和单精度浮点数的计算代价相差无几。</li></ul> <h3 id="_2-1-1-练习"><a href="#_2-1-1-练习" class="header-anchor">#</a> 2.1.1 练习</h3> <p><strong>练习 2.1：</strong> 类型 int、long、long long、short的区别是什么？无符号类型和带符号类型的区别是什么？float 和 double 的区别是什么？</p> <blockquote><p>解答：</p> <p>在 Cpp 语言中，int、long、long long、short 都属于整型，区别是 Cpp 标准规定的尺寸的最小值（即改类型在内存中所占的比特数）不同。其中， short 是短整型，占 16 位；int 是整型，占16位；long 和 long long 均为长整型，分别占 32 位和 64 位。</p> <p>大多数整型都可以划分为无符号类型和带符号类型，在无符号类型中所有比特都用来存储数值，但是仅能表示大于等于 0 的值；带符号类型可以表示整数、负数或者 0。</p> <p>float 和 double 分别是单精度浮点数和双精度浮点数，区别主要是内存中所占的比特数不同，以及默认规定的有效位数不同。</p></blockquote> <p><strong>练习 2.2：</strong> 计算按揭贷款时，对于利率、本金、付款分别应选择何种数据类型？说明你的理由。</p> <blockquote><p>解答：</p> <p>利率、本金、付款既有可能是整数，也有可能是普通的实数。因此应该选择一种浮点类型来表示。float、double、long double，其中 double 和float 的计算代价比较接近且表示范围更广，long double 的计算代价则相对较大，一般情况下没有选择的必要。因此，选择 double 是比较恰当的。</p></blockquote> <h3 id="_2-1-2-类型转换"><a href="#_2-1-2-类型转换" class="header-anchor">#</a> 2.1.2 类型转换</h3> <p>将对象从一种给定的类型转换为另一种相关类型。</p> <ul><li>将一个非布尔类型的算术值赋给布尔类型，初始值为 0 则结果为 false，否则结果为 true。</li> <li>把一个布尔类型赋值给非布尔类型，初始值为 false 结果为 0，初始值为 true 则结果为 1。</li> <li>把一个浮点数赋值给整数类型，会进行近似处理。结果值将仅保留浮点数中小数点之前的部分。</li> <li>把一个整数赋值给浮点类型，小数部分记为 0。如果该整数所占的空间超过了浮点类型的容量，精度可能有损失。</li> <li>赋给无符号类型一个超出它表示范围的值时，结果是初始值对无符号类型表示数值总数取模后的余数。
<ul><li>例如：8 比特大小的 unsigned char 可以表示 0 至 255 区间内的值，如果赋了一个区间以外的值，则实际的结果是该值对 256 取模后所得的余数。因此，如果把 -1 赋给 8 比特大小的 unsigned char 所得的结果是 255。</li></ul></li> <li>赋给带符号类型一个超出它表示范围的值时，结果是未定义的（undefined）。程序可能继续工作、可能崩溃，也可能生成垃圾数据。</li></ul> <hr> <p>无符号数不会小于 0 这一事实同样关系到循环的写法。</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> i <span class="token operator">&gt;=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token operator">--</span>i<span class="token punctuation">)</span>
    std<span class="token double-colon punctuation">::</span>cout <span class="token operator">&lt;&lt;</span> i <span class="token operator">&lt;&lt;</span> std<span class="token double-colon punctuation">::</span>endl<span class="token punctuation">;</span>
<span class="token comment">// 可能你会觉得反正也不会输出负数，打算用无符号数来重写这个循环。</span>
<span class="token comment">// 但是，这个改变却会导致死循环：</span>
<span class="token comment">// 错误：变量 u 永远也不会小于 0，循环条件一直成立</span>
<span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">unsigned</span> u <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span> u <span class="token operator">&gt;=</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token operator">--</span>u<span class="token punctuation">)</span>
    std<span class="token double-colon punctuation">::</span>cout <span class="token operator">&lt;&lt;</span> u <span class="token operator">&lt;&lt;</span> std<span class="token double-colon punctuation">::</span>endl<span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>当 u 等于 0 时会发生什么，这次迭代输出 0 ，然后继续执行 for 语句里的表达时。表达式 --u 从 u 当中减去 1 ，得到的结果 -1 并不满足无符号数的要求，此时像所有表达式范围之外的其他数字一样， -1 被自动转换为一个合法的无符号数。假设 int 类型占 32 位，则当 u 等于 0 时， --u 的结果将会是 4294967295。</p> <p>解决办法是：用 while 循环代替 for 语句</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">unsigned</span> u <span class="token operator">=</span> <span class="token number">11</span><span class="token punctuation">;</span>	<span class="token comment">// 确定要输出的最大数，从比它大 1 的数开始</span>
<span class="token keyword">while</span><span class="token punctuation">(</span>u <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token operator">--</span>u<span class="token punctuation">;</span>			<span class="token comment">// 先减 1，这样最后一次迭代时就会输出 0</span>
    std<span class="token double-colon punctuation">::</span>cout <span class="token operator">&lt;&lt;</span> u <span class="token operator">&lt;&lt;</span> std<span class="token double-colon punctuation">::</span>endl<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>改写后的循环先执行对循环控制变量减 1 操作，这样最后一次迭代时，进入循环的 u 值为 1。此时将其减 1，则这次迭代输出的数就是 0：下一次在检验循环条件时，u 的值等于 0 而无法在进入循环。因为我们要先做减 1 的操作，所以初始化 u 的值应该比要输出的最大值大 1。这里，u 的初始化为 11，输出的最大数为10。</p> <h3 id="_2-1-3-字面值常量"><a href="#_2-1-3-字面值常量" class="header-anchor">#</a> 2.1.3 字面值常量</h3> <p>浮点型字面值表现为一个小数或以科学计数法表示的指数，其中指数部分用 E 和 e 标识：</p> <blockquote><p>3.14159	3.14159E0	0.	0e0	.001</p></blockquote> <p><strong>字符和字符串字面值</strong></p> <p>单引号括起来的一个字符称为 char 型字面值，双引号括起来的零个或多个字符则构成字符串型字面值。</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token char">'a'</span>				<span class="token comment">// 字符字面值</span>
<span class="token string">&quot;Hello World!&quot;</span>	<span class="token comment">// 字符串字面值</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>字符串字面值的类型实际上是由常量字符构成的数组（array）。</p> <p>编译器在每个字符串的结尾处添加一个空字符（<code>'\0'</code>），因此，字符串字面值的实际长度要比它的内容多 1。</p> <p>例如：字面值 <code>'A'</code>表示的就是单独的字符 A，而字符串 <code>&quot;A&quot;</code>则代表了一个字符的数组，包含字母 A、另一个是空字符。</p> <p>如果两个字符串字面值位置紧邻且仅由空格、缩进和换行符分隔，则它们实际上是一个整体。当书写的字符串字面值比较长，写在一行不太合适时，就可以采取分开书写的方式：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token comment">// 分多行书写的字符串字面值</span>
std<span class="token double-colon punctuation">::</span>cout <span class="token operator">&lt;&lt;</span> <span class="token string">&quot;a really, really long string literal &quot;</span>
    		 <span class="token string">&quot;that spans two lines&quot;</span> <span class="token operator">&lt;&lt;</span> std<span class="token double-colon punctuation">::</span>endl<span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p><strong>指定字面值的类型</strong></p> <p><img alt="1701243445524" data-src="https://cdn.jsdelivr.net/gh/xiaose-code/Pictures@main/img/1701243445524.webp" loading="lazy" class="lazy"></p> <h2 id="_2-2-变量"><a href="#_2-2-变量" class="header-anchor">#</a> 2.2 变量</h2> <h3 id="_2-2-1-变量定义"><a href="#_2-2-1-变量定义" class="header-anchor">#</a> 2.2.1 变量定义</h3> <blockquote><p>何为对象？</p> <p>通常情况下，对象是指一块能存储数据并具有某种类型的内存空间。</p></blockquote> <p>初始化不等于赋值，注意区分！</p> <blockquote><p>初始化不是赋值，初始化的含义是创建变量时赋予其一个初始值，而赋值的含义是把对象的当前值擦除，而以一个新值来替代。</p></blockquote> <h3 id="_2-2-2-变量声明和定义的关系"><a href="#_2-2-2-变量声明和定义的关系" class="header-anchor">#</a> 2.2.2 变量声明和定义的关系</h3> <p>如果想声明一个变量而非定义它，就在变量名前添加关键字extern，而且不要显式地初始化变量：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">extern</span> <span class="token keyword">int</span> i<span class="token punctuation">;</span>	<span class="token comment">// 声明 i 而非定义 i</span>
<span class="token keyword">int</span> j<span class="token punctuation">;</span>			<span class="token comment">// 声明并定义 j</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>但是如果给 extern 语句赋一个初值就变成定义了，这么做就抵消了 extern 的作用。</p> <blockquote><p>变量能且只能被定义一次，但是可以被多次声明。</p></blockquote> <blockquote><p><strong>==关键概念：静态类型==</strong></p> <p>Cpp 是一种静态类型 (statically typed) 语言，其含义是在编译阶段检查类型。其中，检查类型的过程称为类型检查 (type checking)。</p></blockquote> <h2 id="_2-3-复合类型"><a href="#_2-3-复合类型" class="header-anchor">#</a> 2.3 复合类型</h2> <h3 id="_2-3-1-引用"><a href="#_2-3-1-引用" class="header-anchor">#</a> 2.3.1 引用</h3> <blockquote><p><strong>当我们使用术语“引用”时，指的其实是“左值引用”</strong></p></blockquote> <ul><li>引用：就是给某个对象起别名，将声明符写成 &amp;d 的形式来定义引用类型，d 是声明的变量名；</li> <li>一般初始化变量时，初始值会被<strong>拷贝</strong>到新建的对象中。然而定义引用时，程序把引用和它的初始值<strong>绑定</strong>在一起，而<strong>不是</strong>将初始值拷贝给引用；</li> <li>一旦绑定便无法更改，因为无法令引用重新绑定到另外一个对象，因此引用必须初始化。</li> <li>为引用赋值，实际上是把值赋给了与引用绑定的对象，获取引用的值，实际上是获取了与引用绑定的对象的值；</li> <li>引用本身不是一个对象，所以不能定义引用的引用。</li></ul> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">int</span> ival <span class="token operator">=</span> <span class="token number">1024</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">&amp;</span>refVal <span class="token operator">=</span> ival<span class="token punctuation">;</span>		<span class="token comment">//refVal指向ival（是ival的另一个名字）</span>
<span class="token keyword">int</span> <span class="token operator">&amp;</span>refVal2<span class="token punctuation">;</span>			<span class="token comment">//报错：引用必须被初始化</span>
refVal <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">;</span>				<span class="token comment">//把2赋给refVal指向的对象，此处即是赋给了ival</span>
<span class="token keyword">int</span> ii <span class="token operator">=</span> refVal<span class="token punctuation">;</span>		<span class="token comment">//与ii = ival执行结果一样</span>
<span class="token keyword">int</span> <span class="token operator">&amp;</span>refVal3 <span class="token operator">=</span> refVal<span class="token punctuation">;</span>	<span class="token comment">//正确：refVal绑定到了那个与refVal绑定的对象上，这里就是绑定到ival上</span>
<span class="token keyword">int</span> i <span class="token operator">=</span> refVal<span class="token punctuation">;</span>			<span class="token comment">//正确：i被初始化为ival的值</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><ul><li>引用只能绑定在对象上，而不能与字面值或某个表达式的计算结果绑定在一起</li> <li>引用的类型要和与之绑定的对象严格匹配</li></ul> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">int</span> <span class="token operator">&amp;</span>refVal4 <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>	 <span class="token comment">//错误：引用类型的初始值必须是一个对象</span>
<span class="token keyword">double</span> dval <span class="token operator">=</span> <span class="token number">3.14</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">&amp;</span>refVal5 <span class="token operator">=</span> dval<span class="token punctuation">;</span> <span class="token comment">//错误：此处引用类型的初始值必须是int型对象</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p><strong>引用的类型要和与之绑定的对象严格匹配，但有两种例外情况：</strong></p> <ol><li>在初始化常量引用时允许用任意表达式作为初始值，只要该表达式的结果能转换成引用的类型即可。</li> <li>允许为一个常量引用绑定非常量的对象、字面值，甚至是个一般表达式。</li></ol> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">&amp;</span>r1 <span class="token operator">=</span> i<span class="token punctuation">;</span><span class="token comment">//允许将const int&amp; 绑定到一个普通int对象上</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">&amp;</span>r2 <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span>  <span class="token comment">//正确：r1是一个常量引用</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">&amp;</span>r3 <span class="token operator">=</span> r1<span class="token operator">*</span><span class="token number">2</span><span class="token punctuation">;</span><span class="token comment">//正确：r3是一个常量引用</span>
<span class="token keyword">int</span> <span class="token operator">&amp;</span>r4 <span class="token operator">=</span> r1<span class="token operator">*</span><span class="token number">2</span><span class="token punctuation">;</span>      <span class="token comment">//正确：r4是一个普通的非常量引用</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h3 id="_2-3-2-指针"><a href="#_2-3-2-指针" class="header-anchor">#</a> 2.3.2 指针</h3> <blockquote><p>与引用类似，指针也实现了对其他对象的间接访问。</p></blockquote> <ul><li>定义指针类型的方法将声明符写成 <code>*d</code> 的形式，d是变量名。如果一条语句中定义了几个指针变量，每个变量前面都必须有符号 <code>*</code>；</li> <li>指针本身就是一个对象，允许对指针赋值和拷贝，在指针的声明周期内它可以先后指向几个不用的对象;</li> <li>指针无须再定义时赋初值，在块作用域内定义的指针如果没有被初始化，也将拥有一个不确定的值。</li></ul> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">int</span> <span class="token operator">*</span>ip1<span class="token punctuation">,</span> <span class="token operator">*</span>ip2<span class="token punctuation">;</span>		<span class="token comment">//ip1和ip2都是直指向int型对象的指针</span>
<span class="token keyword">double</span> dp<span class="token punctuation">,</span> <span class="token operator">*</span>dp2<span class="token punctuation">;</span>	<span class="token comment">//dp2是指向double型对象的指针，dp是double型对象</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>除了有两种情况可以例外，其他所有指针的类型都要和它所指向的对象严格匹配：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">double</span> dval<span class="token punctuation">;</span>
<span class="token keyword">double</span> <span class="token operator">*</span>pd <span class="token operator">=</span> <span class="token operator">&amp;</span>dval<span class="token punctuation">;</span><span class="token comment">//正确：初始值是double型对象的地址</span>
<span class="token keyword">double</span> <span class="token operator">*</span>pd2 <span class="token operator">=</span> pd<span class="token punctuation">;</span>  <span class="token comment">//正确：初始值是指向double对象的指针</span>

<span class="token keyword">int</span> <span class="token operator">*</span>pi <span class="token operator">=</span> pd<span class="token punctuation">;</span>	   <span class="token comment">//错误：指针pi的类型和pd的类型不匹配</span>
pi <span class="token operator">=</span> <span class="token operator">&amp;</span>dval<span class="token punctuation">;</span>		   <span class="token comment">//错误：试图把double型对象的地址赋给int型指针</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>因为在声明语句中指针的类型实际上被用于指定它所指向对象的类型，所以二者必须匹配。如果指针指向了一个其他类型的对象，对该对象的操作将发生错误。</p> <p>第一种例外情况：允许令一个指向常量的指针指向一个非常量对象：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">double</span> pi <span class="token operator">=</span> <span class="token number">3.14</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token keyword">double</span> <span class="token operator">*</span>cptr <span class="token operator">=</span> <span class="token operator">&amp;</span>pi<span class="token punctuation">;</span>
<span class="token keyword">double</span> dval <span class="token operator">=</span> <span class="token number">3.14</span>；<span class="token comment">//dval是一个双精度浮点数，它的值可以改变</span>
cptr <span class="token operator">=</span> <span class="token operator">&amp;</span>dval<span class="token punctuation">;</span>		<span class="token comment">//正确：但是不能通过cptr改变dval的值</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>==<strong>指针值应属下列4种状态之一：</strong>==</p> <ol><li>指向一个对象；</li> <li>指向紧邻对象所占空间的下一个位置；</li> <li>空指针，意味着指针没有指向任何对象；</li> <li>无效指针，也就是上述情况之外的其他值。</li></ol> <p>对指针解引用会得出所指的对象，因此如果给解引用的结果赋值，实际上也就是给指针所指的对象赋值：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token operator">*</span>p <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>	  <span class="token comment">//由符号*得到指针p所指的对象，即可经由p为变量ival赋值</span>
cout <span class="token operator">&lt;&lt;</span> <span class="token operator">*</span>p<span class="token punctuation">;</span> <span class="token comment">//输出0</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><blockquote><p>要搞清楚一条赋值语句到底改变了指针的值还是改变了指针所指对象的值不太容易，<strong>最好的办法就是记住赋值永远改变的是等号左侧的对象</strong>。</p></blockquote> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code>pi <span class="token operator">=</span> <span class="token operator">&amp;</span>ival<span class="token punctuation">;</span>  <span class="token comment">//pi的值被改变，现在pi指向了ival</span>
<span class="token comment">//意思是为pi赋一个新的值，也就是改变了那个存放在pi内的地址值。</span>

<span class="token operator">*</span>pi <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>	 <span class="token comment">//ival的值被改变，指针pi并没有改变</span>
<span class="token comment">//则*pi（也就是指针pi指向的那个对象）发生改变。</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p><strong>==指针相等有以下三种情况：==</strong></p> <ol><li>都为空；</li> <li>都指向同一个对象；</li> <li>都指向了同一个对象的下一地址。</li></ol> <blockquote><p><strong>void*指针</strong>是一种特殊的指针类型，可用于存放任意对象的地址。</p></blockquote> <p><strong>指向指针的引用</strong></p> <p>引用本身不是一个对象，因此不能定义只想引用的指针。但指针式对象，所以存在对指针的引用。</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span>p<span class="token punctuation">;</span>		<span class="token comment">//p是一个int型指针</span>
<span class="token keyword">int</span> <span class="token operator">*</span><span class="token operator">&amp;</span>r <span class="token operator">=</span> p<span class="token punctuation">;</span><span class="token comment">//r是一个对指针p的引用</span>

r <span class="token operator">=</span> <span class="token operator">&amp;</span>i<span class="token punctuation">;</span>		<span class="token comment">//r引用了一个指针，因此给r赋值&amp;i就是令p指向i</span>
<span class="token operator">*</span>r <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>		<span class="token comment">//解引用r得到i，也就是p指向的对象，将i的值改为0</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><blockquote><p>面对一条比较复杂的指针或引用的声明语句时，从右向左阅读有助于弄清楚它的真实含义。</p></blockquote> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">int</span> <span class="token operator">*</span><span class="token operator">&amp;</span>r <span class="token operator">=</span> p<span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>离变量名最近的符号（此例中式&amp;r的符号&amp;）对变量的类型有最直接的影响，因此r是一个引用。声明符的其余部分用以确定r引用的类型是什么，此例中的符号*说明r引用的是一个指针。</p> <h2 id="_2-4-const限定符"><a href="#_2-4-const限定符" class="header-anchor">#</a> 2.4 const限定符</h2> <p>const 对象一旦创建后其值就不能在改变，所以 const 对象必须初始化。</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token function">get_size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//正确：运行时初始化</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span>		 <span class="token comment">//正确：编译时初始化</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> k<span class="token punctuation">;</span>			 <span class="token comment">//错误：k是一个未经初始化的常量</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p><strong>初始化和 const</strong></p> <p>如果利用一个对象去初始化另外一个对象，则它们是不是const都无关紧要：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> ci <span class="token operator">=</span> i<span class="token punctuation">;</span>	<span class="token comment">//正确：i的值被拷贝给了ci</span>
<span class="token keyword">int</span> j <span class="token operator">=</span> ci<span class="token punctuation">;</span>			<span class="token comment">//正确：ci的值被拷贝给了j</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>尽管 ci 是整形常量，但无论如何 ci 中的值还是一个整型数。ci 的常量特征仅仅在执行改变 ci 的操作时才会发挥作用。当用 ci 去初始化j时，根本无须在意 ci 是不是一个常量。拷贝一个对象的值并不会改变它，一旦拷贝完成，新的对象就和原来的对象没什么关系了。</p> <p><strong>默认const对象仅在文件内有效</strong></p> <p>默认情况下，const对象被设定为仅在文件内有效。当多个文件中出现了同名的const变量时，其实等同于在不同文件中分别定义了独立的变量。</p> <p>如果我们不希望编译器为每个文件分别生成独立的变量，想要只在一个文件中定义const，而在其他多个文件中声明并使用它。</p> <p>==解决办法是，对于const变量不管是声明还是定义都添加extern关键字，== 这样她只需定义一次就可以了：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token comment">//file_1.cc定义并初始化了一个常量，该常量能被其他文件访问</span>
<span class="token keyword">extern</span> <span class="token keyword">const</span> <span class="token keyword">int</span> bufSize <span class="token operator">=</span> <span class="token function">fcn</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//file_1.h头文件</span>
<span class="token keyword">extern</span> <span class="token keyword">const</span> <span class="token keyword">int</span> bufSize<span class="token punctuation">;</span><span class="token comment">//与file_1.cc中定义的bufSize是同一个</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><blockquote><p>Note：如果想在多个文件之间共享 const 对象，必须在变量的定义之前添加 extern 关键字。</p></blockquote> <h3 id="_2-4-1-const-的引用"><a href="#_2-4-1-const-的引用" class="header-anchor">#</a> 2.4.1 const 的引用</h3> <p>对常量的引用不能被用作修改它所绑定的对象：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">int</span> ci <span class="token operator">=</span> <span class="token number">1024</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">&amp;</span>r1 <span class="token operator">=</span> ci<span class="token punctuation">;</span>  <span class="token comment">//正确：引用及其对应的对象都是常量</span>
r1 <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span>		   	 <span class="token comment">//错误：r1是对常量的引用</span>
<span class="token keyword">int</span> <span class="token operator">&amp;</span>r2 <span class="token operator">=</span> ci<span class="token punctuation">;</span>	   	 <span class="token comment">//错误：试图让一个非常量引用指向一个常量对象</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>因为不允许直接为 ci 赋值，当然也就不能通过引用去改变ci。因此，对 r2 的初始化是错误的。假设该初始化合法，则可以通过 r2 来改变它引用对象的值，这显然是不正确的。</p> <blockquote><p>术语：常量引用是对 const 的引用</p></blockquote> <p><strong>初始化和对const的引用</strong></p> <p><strong>引用的类型要和与之绑定的对象严格匹配，但有两种例外情况：</strong></p> <ol><li>在初始化常量引用时允许用任意表达式作为初始值，只要该表达式的结果能转换成引用的类型即可。</li> <li>允许为一个常量引用绑定非常量的对象、字面值，甚至是个一般表达式。</li></ol> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">&amp;</span>r1 <span class="token operator">=</span> i<span class="token punctuation">;</span>	 <span class="token comment">//允许将const int&amp; 绑定到一个普通int对象上</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">&amp;</span>r2 <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span>  <span class="token comment">//正确：r1是一个常量引用</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">&amp;</span>r3 <span class="token operator">=</span> r1<span class="token operator">*</span><span class="token number">2</span><span class="token punctuation">;</span><span class="token comment">//正确：r3是一个常量引用</span>
<span class="token keyword">int</span> <span class="token operator">&amp;</span>r4 <span class="token operator">=</span> r1<span class="token operator">*</span><span class="token number">2</span><span class="token punctuation">;</span>      <span class="token comment">//正确：r4是一个普通的非常量引用</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>==要理解这种例外情况：最简单的办法是弄清楚当一个常量引用被绑定到另外一种类型上时到底发生了什么：==</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">double</span> dval <span class="token operator">=</span> <span class="token number">3.14</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">&amp;</span>ri <span class="token operator">=</span> dval<span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>此处 ri 引用了一个 int 型的数，对 ri 的操作应该是整数运算，但 dval 是一个双精度浮点数而非整数。因此为了确保让 ri 绑定一个整数，编译器把上述代码变成了如下形式：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">int</span> temp <span class="token operator">=</span> dval<span class="token punctuation">;</span>	<span class="token comment">//由双精度浮点数生成一个临时的整形常量</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">&amp;</span>ri <span class="token operator">=</span> temp<span class="token punctuation">;</span>	<span class="token comment">//让ri绑定这个临时量</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>在这种情况下，ri 绑定了一个临时量对象。对临时变量操作是被归为非法的，因为对临时变量的操作并不会影响 dval ，这并没有什么意义。</p> <p><strong>对const的引用可能引用一个并非const的对象</strong></p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">&amp;</span>r1 <span class="token operator">=</span> i<span class="token punctuation">;</span>		<span class="token comment">//引用ri绑定对象i</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">&amp;</span>r2 <span class="token operator">=</span> i<span class="token punctuation">;</span>  <span class="token comment">//r2也绑定对象i，但是不允许通过r2修改i的值</span>
r1 <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>				<span class="token comment">//r1并非常量，i的值修改为0</span>
r2 <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>				<span class="token comment">//错误：r2是一个常量引用</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>r2 绑定（非常量）整数 i 是合法的行为。然而，不允许通过 r2 修改i的值。尽管如此，i 的值仍然允许通过其他途径修改，既可以直接给i赋值，也可以通过像 r1 一样绑定到i的其他引用来修改。</p> <h3 id="_2-4-2-指针和-const"><a href="#_2-4-2-指针和-const" class="header-anchor">#</a> 2.4.2 指针和 const</h3> <p><strong>==要想存放常量对象的地址，只能使用指向常量的指针：==</strong></p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">double</span> pi <span class="token operator">=</span> <span class="token number">3.14</span><span class="token punctuation">;</span>		<span class="token comment">//pi是个常量，它的值不能改变</span>
<span class="token keyword">double</span> <span class="token operator">*</span>ptr <span class="token operator">=</span> <span class="token operator">&amp;</span>pi<span class="token punctuation">;</span>			<span class="token comment">//错误：ptr是一个普通指针</span>
<span class="token keyword">const</span> <span class="token keyword">double</span> <span class="token operator">*</span>cptr <span class="token operator">=</span> <span class="token operator">&amp;</span>pi<span class="token punctuation">;</span>	<span class="token comment">//正确：cptr可以指向一个双精度常量</span>
<span class="token operator">*</span>cptr <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span>					<span class="token comment">//错误：不能给*cptr赋值</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>前面提到，指针的类型必须与其所指对象的类型一致，但是有两个例外情况：</p> <p>==第一种例外情况：允许令一个指向常量的指针指向一个非常量对象：==</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">double</span> pi <span class="token operator">=</span> <span class="token number">3.14</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token keyword">double</span> <span class="token operator">*</span>cptr <span class="token operator">=</span> <span class="token operator">&amp;</span>pi<span class="token punctuation">;</span>
<span class="token keyword">double</span> dval <span class="token operator">=</span> <span class="token number">3.14</span><span class="token punctuation">;</span>			<span class="token comment">//dval是一个双精度浮点数，它的值可以改变</span>
cptr <span class="token operator">=</span> <span class="token operator">&amp;</span>dval<span class="token punctuation">;</span>				<span class="token comment">//正确：但是不能通过cptr改变dval的值</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>和常量引用一样，指向常量的指针也没有规定其所指的对象必须是一个常量。所谓指向常量的指针仅仅要求不能通过该指针改变对象的值，而没有规定那个对象的值不能通过其他途径改变。</p> <blockquote><p>Tip：可以这样想，所谓指向常量的指针或引用，不过是指针或引用 “自以为是” 罢了，它们觉得自己指向了常量，所以自觉地不去改变所指对象地值。</p></blockquote> <p><strong>const指针</strong></p> <p>指针是对象而引用不是，因此就像其他对象类型一样，允许把指针本身定位常量。</p> <p>常量指针必须初始化，而且一旦初始化完成，则它的值（也就是存放在指针中的那个地址）就不能再改变了。</p> <p>把<code>*</code>放在 const 关键字之前用以说明指针是一个常量，这样的书写形式隐含着一层意味，即不变的是指针本身的值而非指向的那个值：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">int</span> errNumb <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span><span class="token keyword">const</span> curErr <span class="token operator">=</span> <span class="token operator">&amp;</span>errNumb<span class="token punctuation">;</span> <span class="token comment">//curErr将一直指向errNumb</span>
<span class="token keyword">const</span> <span class="token keyword">double</span> pi <span class="token operator">=</span> <span class="token number">3.14159</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token keyword">double</span> <span class="token operator">*</span><span class="token keyword">const</span> pip <span class="token operator">=</span> <span class="token operator">&amp;</span>pi<span class="token punctuation">;</span><span class="token comment">//pip是一个指向常量对象的常量指针</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>==要想弄清楚这些声明的含义最行之有效的办法是从右向左阅读。==</p> <p>离 curErr 最近的的符号是const，意味着 curErr 本身是一个常量对象，对象的类型由声明符的其余部分确定。声明符中的下一个符号是*，意思是 curErr 是一个常量指针。指针存储的那个地址不能改变，但是指向的一个一般的非常量整数，那么就完全可以用curErr去修改 errNumb 的值。</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token operator">*</span>pip <span class="token operator">=</span> <span class="token number">2.72</span><span class="token punctuation">;</span>	<span class="token comment">//错误：pip是一个指向常量的指针</span>
<span class="token comment">//如果curErr所指的对象（也就是errNumb）的值不为0</span>
<span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">*</span>curErr<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">errorHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token operator">*</span>curErr <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span><span class="token comment">//正确：把curErr所指的对象的值重置</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><h3 id="_2-4-3-顶层-const"><a href="#_2-4-3-顶层-const" class="header-anchor">#</a> 2.4.3 顶层 const</h3> <p>指针本身是不是常量以及指针所指的是不是一个常量就是两个相互独立的问题。</p> <ul><li><p><strong>顶层const（top-level const）表示指针本身是个常量；</strong></p> <ul><li>顶层const可以表示任意的对象是常量，这一点对任何数据类型都适用，如算术类型、类、指针等。</li></ul></li> <li><p><strong>底层const（low-level const）表示指针所指的对象是一个常量。</strong></p> <ul><li>底层const则与指针和引用等符合类型的基本类型部分有关。</li></ul></li></ul> <p>==特殊的是：指针类型既可以是顶层const也可以是底层const。==</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> <span class="token operator">*</span><span class="token keyword">const</span> p1 <span class="token operator">=</span> <span class="token operator">&amp;</span>i<span class="token punctuation">;</span>			<span class="token comment">//不能改变p1的值，这是一个顶层const</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> ci <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span> 			<span class="token comment">//不能改变ci的值，这是一个顶层const</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">*</span>p2 <span class="token operator">=</span> <span class="token operator">&amp;</span>ci<span class="token punctuation">;</span>		<span class="token comment">//允许改变p2的值，这是一个底层const</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">*</span><span class="token keyword">const</span> p3 <span class="token operator">=</span> p2<span class="token punctuation">;</span>	<span class="token comment">//靠右的const是顶层const，靠左的是底层const</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">&amp;</span>r <span class="token operator">=</span> ci<span class="token punctuation">;</span>			<span class="token comment">//用于声明引用的const都是底层const</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>当执行对象的拷贝操作时，常量是顶层const还是底层const区别明显：</p> <p>顶层const不受什么影响：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code>i <span class="token operator">=</span> ci<span class="token punctuation">;</span>	<span class="token comment">//正确：拷贝ci的值，ci是一个顶层const，对此操作无影响</span>
p2 <span class="token operator">=</span> p3<span class="token punctuation">;</span><span class="token comment">//正确：p2和p3指向的对象类型相同，p3顶层const的部分不影响</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p><strong>底层const的限制不能忽视：</strong></p> <p>当执行对象的拷贝操作时，拷入和拷出的对象必须具有相同的底层const资格，或者两个对象的数据类型必须能够转换。<strong>一般来说，非常量可以转换成常量，反之则不行：</strong></p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">int</span> <span class="token operator">*</span>p <span class="token operator">=</span> p3<span class="token punctuation">;</span>	  <span class="token comment">//错误：p3包含底层const的定义，而p没有</span>
p2 <span class="token operator">=</span> p3<span class="token punctuation">;</span>		  <span class="token comment">//正确：p2和p3都是底层const</span>
p2 <span class="token operator">=</span> <span class="token operator">&amp;</span>i<span class="token punctuation">;</span>		  <span class="token comment">//正确：int* 能转换成const int*</span>
<span class="token keyword">int</span> <span class="token operator">&amp;</span>r <span class="token operator">=</span> ci<span class="token punctuation">;</span>	  <span class="token comment">//错误：普通的int&amp;不能绑定到int常量上</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">&amp;</span>r2 <span class="token operator">=</span> i<span class="token punctuation">;</span><span class="token comment">//正确：const int&amp;可以绑定到一个普通int上</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h3 id="_2-4-4-constexpr-和常量表达式"><a href="#_2-4-4-constexpr-和常量表达式" class="header-anchor">#</a> 2.4.4 constexpr 和常量表达式</h3> <p>常量表达式（const expression）是指值不会改变并且在编译过程就能得到计算结果的表达式。</p> <p>属于常量表达式的：</p> <ol><li>字面值；</li> <li>用常量表达式初始化的 const 对象也是常量表达式。</li></ol> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">int</span> max_files <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span>		<span class="token comment">//max_files是常量表达式</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> limit <span class="token operator">=</span> max_files <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span><span class="token comment">//limit是常量表达式</span>
<span class="token keyword">int</span> staff_size <span class="token operator">=</span> <span class="token number">27</span><span class="token punctuation">;</span>			<span class="token comment">//staff_size不是常量表达式</span>
<span class="token keyword">const</span> <span class="token keyword">int</span> sz <span class="token operator">=</span> <span class="token function">get_size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>		<span class="token comment">//sz不是常量表达式</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>尽管 sz 本身是一个常量，但它地具体值直到运行时才能获取到，所以也不是常量表达式。</p> <p><strong>constexpr 常量</strong></p> <p>Cpp11 新标准规定，允许将声明变量声明为 constexpr 类型以便由编译器来验证变量地值是否是一个常量表达式。</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">constexpr</span> <span class="token keyword">int</span> mf <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span>		 <span class="token comment">// 20 是常量表达式</span>
<span class="token keyword">constexpr</span> <span class="token keyword">int</span> limit <span class="token operator">=</span> mf <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span><span class="token comment">// mf+1 是常量表达式</span>
<span class="token keyword">constexpr</span> <span class="token keyword">int</span> sz <span class="token operator">=</span> <span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>	 <span class="token comment">//只有size是一个constexpr函数时才是一条正确的声明语句</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><blockquote><p>一般来说，如果你认定变量是一个常量表达式，那就把它声明成 constexpr 类型。</p></blockquote> <p><strong>字面值类型</strong></p> <blockquote><p>字面值类型指的是：类型简单、值也显而易见、容易得到，就把它们称为“字面值类型”。</p></blockquote> <p>比如：</p> <ul><li>属于字面值类型的：算术类型、引用、指针</li> <li>不属于字面值类型的：自定义类、IO 库、string 类型</li></ul> <p>指针和引用都能定义成 constexpr ，但它们的初始值都受到严格限制。一个 constexpr 指针的初始值必须是 nullptr 或者 0，或者是存储与某个固定地址中的对象。</p> <p><strong>指针和 constexpr</strong></p> <p>必须明确一点：在 constexpr 声明中如果定义了一个指针，限定符 constexpr 仅对指针有效，与指针所指的对象无关；</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">int</span> <span class="token operator">*</span>p <span class="token operator">=</span> <span class="token keyword">nullptr</span><span class="token punctuation">;</span>  	<span class="token comment">// p是一个指向整形常量的指针</span>
<span class="token keyword">constexpr</span> <span class="token keyword">int</span> <span class="token operator">*</span>q <span class="token operator">=</span> <span class="token keyword">nullptr</span><span class="token punctuation">;</span>	<span class="token comment">// q是一个指向整数的常量指针</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>p和q的类型相差甚远：</p> <ul><li>p是一个指向常量的指针。</li> <li>q是一个常量指针，关键在于 constexpr 把它所定义的对象置为了顶层 const。</li></ul> <h2 id="_2-5-处理类型"><a href="#_2-5-处理类型" class="header-anchor">#</a> 2.5 处理类型</h2> <h3 id="_2-5-1-类型别名"><a href="#_2-5-1-类型别名" class="header-anchor">#</a> 2.5.1 类型别名</h3> <blockquote><p>类型别名（type alias）是一个名字，它是某种类型的同义词。</p></blockquote> <p>传统的方式，使用关键字 typedef 定义类型别名的两种方法：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">typedef</span> <span class="token keyword">double</span> wages<span class="token punctuation">;</span>	<span class="token comment">// wages 是 double 的同义词</span>
<span class="token keyword">typedef</span> wages base<span class="token punctuation">,</span> <span class="token operator">*</span>p<span class="token punctuation">;</span>	<span class="token comment">// base 是 double 的同义词，p 是 double* 的同义词</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>新规定，使用别名声明：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">using</span> SI <span class="token operator">=</span> Sales_item<span class="token punctuation">;</span>	<span class="token comment">// SI 是 Sales_item 的同义词</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>类型别名和类型的名字等价，只要是类型的名字能出现的地方，就能使用类型别名：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code>wages hourly<span class="token punctuation">,</span> weekly<span class="token punctuation">;</span>	<span class="token comment">// 等价于 double hourly、weekly</span>
SI item<span class="token punctuation">;</span>				<span class="token comment">// 等价于 Sales_item item</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p><strong>指针、常量和类型别名</strong></p> <blockquote><p>书中主要讲了在Cpp中使用类型别名时可能出现的误解，特别是涉及到指针、常量和类型别名组合的情况。 <strong>==不可以简单地将类型别名替换为其原始类型==</strong></p></blockquote> <p>让我逐步解释一下：</p> <ol><li><p><strong>类型别名的定义：</strong></p> <div class="language-cpp line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">typedef</span> <span class="token keyword">char</span> <span class="token operator">*</span>pstring<span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>这里定义了一个类型别名 <code>pstring</code>，它是 <code>char*</code> 的别名，即指向字符的指针。</p></li> <li><p><strong>使用类型别名和常量的声明：</strong></p> <div class="language-cpp line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> pstring cstr <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>这一行声明了一个常量指针 <code>cstr</code>，它指向字符 (<code>char</code>)，并被声明为常量。但是，由于 <code>pstring</code> 是 <code>char*</code> 的别名，这实际上是一个指向字符的常量指针。</p></li> <li><p><strong>使用类型别名和指针的声明：</strong></p> <div class="language-cpp line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> pstring <span class="token operator">*</span>ps<span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>这一行声明了一个指针 <code>ps</code>，它指向的对象是指向字符的常量指针。</p></li> <li><p><strong>错误的理解：</strong>
作者指出，在阅读这样的声明时，<strong>人们可能错误地尝试将类型别名替换为其原始类型</strong>，以理解声明的含义。例如，尝试将 <code>const pstring cstr</code> 理解为 <code>const char *cstr</code>。这是错误的，因为 <code>const pstring</code> 表示指向字符的常量指针，而不是指向常量字符的指针。</p></li> <li><p><strong>改写示例：</strong></p> <div class="language-cpp line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span>cstr <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>这是错误理解的改写，它将 <code>const pstring cstr</code> 错误地理解为 <code>const char *cstr</code>。这样改写的结果是声明了一个指向常量字符的指针，而不是指向字符的常量指针。这两种声明的含义是截然不同的。</p></li> <li><p>正确的改写应该是：</p> <div class="language-cpp line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">char</span> <span class="token operator">*</span><span class="token keyword">const</span> cstr <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>这表示 <code>cstr</code> 是一个指向字符的常量指针，并且它本身也是一个常量。这样的改写保持了原始声明的含义，即 <code>cstr</code> 是一个指向字符的常量指针。</p></li></ol> <p>总的来说，这段话强调了在使用类型别名时，特别是涉及到指针和常量的情况下，需要正确理解类型别名的含义，而不能简单地将其替换为原始类型。这有助于避免在代码理解上的混淆和错误。</p> <h3 id="_2-5-2-auto-类型说明符"><a href="#_2-5-2-auto-类型说明符" class="header-anchor">#</a> 2.5.2 auto 类型说明符</h3> <p><strong>auto 可在一条语句中声明多个变量，但是初始基本数据类型都必须一样：</strong></p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">auto</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token operator">*</span>p <span class="token operator">=</span> <span class="token operator">&amp;</span>i<span class="token punctuation">;</span>	<span class="token comment">// 正确：i 是整数、p是整数指针</span>
<span class="token keyword">auto</span> sz <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> pi <span class="token operator">=</span> <span class="token number">3.14</span><span class="token punctuation">;</span>	<span class="token comment">// 错误：sz 和 pi 的类型不一致</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p><strong>复合类型、常量、auto</strong></p> <p>auto 一般会忽略掉顶层 const，同时底层 const 则会保留下来，比如当初始值是一个指向常量的指针时：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">int</span> ci <span class="token operator">=</span> i<span class="token punctuation">,</span> <span class="token operator">&amp;</span>cr <span class="token operator">=</span> ci<span class="token punctuation">;</span>
<span class="token keyword">auto</span> b <span class="token operator">=</span> ci<span class="token punctuation">;</span>		<span class="token comment">// b 是一个整数(ci 的顶层const 特性被忽略掉了)</span>
<span class="token keyword">auto</span> c <span class="token operator">=</span> cr<span class="token punctuation">;</span>		<span class="token comment">// c 是一个整数(cr 是 ci 的别名，ci 本身是一个顶层 const)</span>
<span class="token keyword">auto</span> d <span class="token operator">=</span> <span class="token operator">&amp;</span>i<span class="token punctuation">;</span>		<span class="token comment">// d 是一个整型指针(整数的地址就是指向整数的指针)</span>
<span class="token keyword">auto</span> e <span class="token operator">=</span> <span class="token operator">&amp;</span>ci<span class="token punctuation">;</span>		<span class="token comment">// e 是一个指向整数常量的指针(对常量对象取地址是一种底层 const)</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>如果希望推断出的 auto 类型是一个顶层 const，需要明确指出：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">auto</span> f <span class="token operator">=</span> ci<span class="token punctuation">;</span>	<span class="token comment">// ci 的推演类型是 int，f 是 const int</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>还可以将引用的类型设为 auto，此时原来的初始化规则仍然适用:</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">auto</span> <span class="token operator">&amp;</span>g <span class="token operator">=</span> ci<span class="token punctuation">;</span>		<span class="token comment">// g 是一个整型常量引用，绑定到 ci</span>
<span class="token keyword">auto</span> <span class="token operator">&amp;</span>h <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span>		<span class="token comment">// 错误:不能为非常量引用绑定字面值</span>
<span class="token keyword">const</span> <span class="token keyword">auto</span> <span class="token operator">&amp;</span>j <span class="token operator">=</span> <span class="token number">42</span><span class="token punctuation">;</span>	<span class="token comment">// 正确:可以为常量引用绑定字面值</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>设置一个类型为auto的引用时，初始值中的顶层常量属性仍然保留。和往常一样，如果我们给初始值绑定一个引用，则此时的常量就不是顶层常量了。
要在一条语句中定义多个变量，切记，符号 <code>&amp;</code> 和 <code>*</code> 只从属于某个声明符，而非基本数据类型的一部分，因此初始值必须是同一种类型:</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">auto</span> k <span class="token operator">=</span> ci<span class="token punctuation">,</span> <span class="token operator">&amp;</span>l <span class="token operator">=</span> i<span class="token punctuation">;</span>	<span class="token comment">// k 是整数，1 是整型引用</span>
<span class="token keyword">auto</span> <span class="token operator">&amp;</span>m <span class="token operator">=</span> ci<span class="token punctuation">,</span><span class="token operator">*</span>p <span class="token operator">=</span> <span class="token operator">&amp;</span>ci<span class="token punctuation">;</span> 	<span class="token comment">// m 是对整型常量的引用，p 是指向整型常量的指针</span>
						<span class="token comment">// 错误: i 的类型是 int 而 &amp;ci 的类型是 const int</span>
<span class="token keyword">auto</span> <span class="token operator">&amp;</span>n <span class="token operator">=</span> i<span class="token punctuation">,</span> <span class="token operator">*</span>p2 <span class="token operator">=</span> <span class="token operator">&amp;</span>ci<span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><h3 id="_2-5-3-decltype-类型指示符"><a href="#_2-5-3-decltype-类型指示符" class="header-anchor">#</a> 2.5.3 decltype 类型指示符</h3> <p>Cpp11 新标准引入的第二种类型说明符 decltype，它的作用是选择并返回操作数的数据类型。</p> <p>在此过程中，编译器分析表达式并得到它的类型，却不实际计算表达式的值：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">decltype</span><span class="token punctuation">(</span><span class="token function">f</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> sum <span class="token operator">=</span> x<span class="token punctuation">;</span>	<span class="token comment">// sum 的类型就是函数 f 的返回类型</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>编译器不会实际调用函数 f，而是使用当调用发生时 f 的返回值类型作为 sum 的类型。</p> <p>decltype 处理顶层 const 和引用的方式与 auto 有些许不同。如果 decltype 使用的表达式是一个变量,则 decltype 返回该变量的类型(包括顶层 const 和引用在内)：</p> <div class="language-CPP line-numbers-mode"><pre class="language-cpp"><code><span class="token keyword">const</span> <span class="token keyword">int</span> ci <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token operator">&amp;</span>cj <span class="token operator">=</span> ci<span class="token punctuation">;</span>
<span class="token keyword">decltype</span><span class="token punctuation">(</span>ci<span class="token punctuation">)</span> x <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>			<span class="token comment">// x 的类型是 const int</span>
<span class="token keyword">decltype</span><span class="token punctuation">(</span>cj<span class="token punctuation">)</span> y <span class="token operator">=</span> xi<span class="token punctuation">;</span>		<span class="token comment">// y 的类型是 const int&amp;，y 绑定到变量 x</span>
<span class="token keyword">decltype</span><span class="token punctuation">(</span>cj<span class="token punctuation">)</span> z<span class="token punctuation">;</span>				<span class="token comment">// 错误: z 是一个引用，必须初始化</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><h2 id="小结"><a href="#小结" class="header-anchor">#</a> 小结</h2> <p>类型是 Cpp 编程的基础。</p> <p>类型规定了其对象的存储要求和所能执行的操作。Cpp 语言提供了一套基础内置类型，如 int 和 char 等，这些类型与实现它们的机器硬件密切相关。类型分为非常量和常量，一个常量对象必须初始化，而且一旦初始化其值就不能再改变。此外，还可以定义复合类型，如指针和引用等。复合类型的定义以其他类型为基础。</p> <p>Cpp 语言允许用户以类的形式自定义类型。Cpp 库通过类提供了一套高级抽象类型，如输入输出和string 等。</p></div></div> <!----> <div class="page-edit"><!----> <!----> <div class="last-updated"><span class="prefix">上次更新:</span> <span class="time">2024/6/3 14:54:44</span></div></div> <div class="page-nav-wapper"><div class="page-nav-centre-wrap"><a href="/pages/48ac45/" class="page-nav-centre page-nav-centre-prev"><div class="tooltip">第9章 标准库</div></a> <a href="/pages/518856/" class="page-nav-centre page-nav-centre-next"><div class="tooltip">Cpp11新标准</div></a></div> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/pages/48ac45/" class="prev">第9章 标准库</a></span> <span class="next"><a href="/pages/518856/">Cpp11新标准</a>→
      </span></p></div></div></div> <!----></main></div> <div class="footer"><!----> 
  Theme by
  <a href="https://github.com/xugaoyi/vuepress-theme-vdoing" target="_blank" title="本站主题">Vdoing</a> 
    | Copyright © 2023-2025
    <span>霜晨月</span></div> <div class="buttons"><div title="返回顶部" class="button blur go-to-top iconfont icon-fanhuidingbu" style="display:none;"></div> <div title="去评论" class="button blur go-to-comment iconfont icon-pinglun" style="display:none;"></div> <div title="主题模式" class="button blur theme-mode-but iconfont icon-zhuti"><ul class="select-box" style="display:none;"><li class="iconfont icon-zidong">
          跟随系统
        </li><li class="iconfont icon-rijianmoshi">
          浅色模式
        </li><li class="iconfont icon-yejianmoshi">
          深色模式
        </li><li class="iconfont icon-yuedu">
          阅读模式
        </li></ul></div></div> <!----> <!----> <!----></div><div class="global-ui"><canvas id="vuepress-canvas-cursor"></canvas></div></div>
    <script src="/assets/js/app.67adcfd9.js" defer></script><script src="/assets/js/4.9aaa1650.js" defer></script><script src="/assets/js/1.5474518c.js" defer></script><script src="/assets/js/3.593d14fc.js" defer></script><script src="/assets/js/48.15ff5726.js" defer></script>
  </body>
</html>
